package multi_thread.train;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * @author Cheng Jun
 * Description: 测试类：验证奇葩的想法和逻辑
 * @version 1.0
 * @date 2022/5/11 16:01
 */
public class MyTest {


    public static void main(String[] args) throws InterruptedException, ExecutionException {
        // synchronized 抢占锁时，抢到锁的顺序类似栈，后抢的，会先得到锁
        // 多个线程 wait，被notify 唤醒的顺序类似队列，先wait的，会先被唤醒
        // 验证 notify 是不是随机唤醒等待的线程。
        // testNotify();

        // 测试创建 1000个对象 需要多长时间
        // long startMilli = System.currentTimeMillis();
        // for (int i = 0; i < 1000; i++) {
        //     new Node(i, String.valueOf(i));
        // }
        // long endMilli = System.currentTimeMillis();
        // // endMilli - startMilli = 2~3
        // System.out.println("endMilli - startMilli = " + (endMilli - startMilli));

        // 测试 LongAdder 方法
        // LongAdder atomicNum = new LongAdder();
        // System.out.println(atomicNum);
        // atomicNum.add(2);
        // System.out.println(atomicNum);

        // 测试使用 Runnable 创建 FutureTask
        // testFutureTask();

        // 测试线程池关闭后，继续提交任务的拒绝策略
        // 拒绝策略发生在两种情况下：1.线程池被关闭，2. workQueue 容量达到最大值且线程池中线程数量达到最大值
        // 用阻塞线程的好处在于，阻塞线程 自带 唤醒和等待 机制，take 和 put方法自带阻塞，比如核心线程数满了workQueue达到最大值，此时put阻塞，cpu去抓紧创建 非核心线程
        // 线程池创建线程时，获取全局锁，其它线程都要阻塞
        // testRejectTask();

        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(() -> {
                System.out.println(Thread.currentThread().getName());
            });
            thread.start();
            thread.join();
        }

    }

    static void testNotify() throws InterruptedException {
        Object lock = new Object();
        Thread thread0 = new Thread(() -> {
            synchronized (lock) {
                try {
                    System.out.println(Thread.currentThread().getName() + " 获得lock");
                    Thread.sleep(5_000);
                    // lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread thread1 = new Thread(() -> {
            synchronized (lock) {
                try {
                    System.out.println(Thread.currentThread().getName() + " 获得lock");
                    Thread.sleep(500);
                    lock.wait();
                    System.out.println(Thread.currentThread().getName() + " 继续执行");
                    lock.notify();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        Thread thread2 = new Thread(() -> {
            synchronized (lock) {
                try {
                    System.out.println(Thread.currentThread().getName() + " 获得lock");
                    Thread.sleep(500);
                    lock.wait();
                    System.out.println(Thread.currentThread().getName() + " 继续执行");
                    lock.notify();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        Thread thread3 = new Thread(() -> {
            synchronized (lock) {
                try {
                    System.out.println(Thread.currentThread().getName() + " 获得lock");
                    Thread.sleep(500);
                    lock.wait();
                    System.out.println(Thread.currentThread().getName() + " 继续执行");
                    lock.notify();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        Thread thread4 = new Thread(() -> {
            synchronized (lock) {
                try {
                    System.out.println(Thread.currentThread().getName() + " 获得lock");
                    Thread.sleep(500);
                    lock.wait();
                    System.out.println(Thread.currentThread().getName() + " 继续执行");
                    lock.notify();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        thread0.start();
        Thread.sleep(1_000);
        thread1.start();

        Thread.sleep(1_000);
        thread2.start();

        Thread.sleep(1_000);
        thread3.start();

        Thread.sleep(1_000);
        thread4.start();

        Thread.sleep(3_000);

        synchronized (lock) {
            System.out.println(Thread.currentThread().getName() + " 调用notify()");
            lock.notify();
        }
    }

    static void testFutureTask() throws ExecutionException, InterruptedException {
        Runnable runnable = () -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("测试 FutureTask 能不能获取 Runnable的运行结果");
        };
        FutureTask futureTask = new FutureTask<>(runnable, "运行成功");
        new Thread(futureTask).start();
        System.out.println(futureTask.get());
        System.out.println("因为 futureTask.get() 是阻塞方法，所以主线程会被阻塞！");
    }

    static class Node {
        private int waitStatus;
        private String threadName;

        public Node(int waitStatus, String threadName) {
            this.waitStatus = waitStatus;
            this.threadName = threadName;
        }
    }

    static void testRejectTask() throws InterruptedException {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(2), new ThreadPoolExecutor.AbortPolicy());
        for (int i = 0; i < 4; i++) {
            int num  = i;
            Runnable task = () -> {
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + " num: " + num);
            };
            threadPoolExecutor.execute(task);
            threadPoolExecutor.shutdown();
        }

    }

}
